import { Field } from 'vant'

const bem = createBEM('van-field')

export default {
  extends: Field,
  methods: {
    updateValue(value, trigger = 'onChange') {
      value = isDef(value) ? String(value) : ''

      // native maxlength have incorrect line-break counting
      // see: https://github.com/vant-ui/vant/issues/5033
      const { maxlength } = this
      if (isDef(maxlength) && value.length > maxlength) {
        if (this.value && this.value.length === +maxlength) {
          ({ value } = this)
        } else {
          value = value.slice(0, maxlength)
        }
      }

      if (this.formatter && trigger === this.formatTrigger) {
        value = this.formatter(value)
      }

      const { input } = this.$refs
      if (input && value !== input.value) {
        input.value = value
      }

      if (value !== this.value) {
        this.$emit('input', value)
      }
    },
    genInput() {
      const { type } = this
      const disabled = this.getProp('disabled')
      const readonly = this.getProp('readonly')
      const inputSlot = this.slots('input')
      const inputAlign = this.getProp('inputAlign')

      if (inputSlot) {
        return (
          <div
            class={bem('control', [inputAlign, 'custom'])}
            onClick={this.onClickInput}
          >
            {inputSlot}
          </div>
        )
      }

      const inputProps = {
        ref: 'input',
        class: bem('control', inputAlign),
        domProps: {
          value: this.value
        },
        attrs: {
          ...this.$attrs,
          name: this.name,
          disabled,
          readonly,
          placeholder: this.placeholder
        },
        on: this.listeners,
        // add model directive to skip IME composition
        directives: [
          {
            name: 'model',
            value: this.value
          }
        ]
      }

      if (type === 'textarea') {
        return <textarea {...inputProps} />
      }

      let inputMode

      // type="number" is weird in iOS, and can't prevent dot in Android
      // so use inputmode to set keyboard in modern browsers
      if (type === 'number') {
        inputMode = 'decimal'
      }

      if (type === 'digit') {
        inputMode = 'numeric'
      }

      return <input type={type} inputMode={inputMode} cursor-spacing={10} {...inputProps} />
    }
  }
}

function gen(name, mods) {
  if (!mods) {
    return ''
  }

  if (typeof mods === 'string') {
    return ` ${name}--${mods}`
  }

  if (Array.isArray(mods)) {
    return mods.reduce((ret, item) => ret + gen(name, item), '')
  }

  return Object.keys(mods).reduce(
    (ret, key) => ret + (mods[key] ? gen(name, key) : ''),
    ''
  )
}

export function createBEM(name) {
  return function(el, mods) {
    if (el && typeof el !== 'string') {
      mods = el
      el = ''
    }

    el = el ? `${name}__${el}` : name

    return `${el}${gen(el, mods)}`
  }
}

export function isDef(val) {
  return val !== undefined && val !== null
}
